<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>分类: 面试 | 小小程序员</title><meta name="author" content="十一星野"><meta name="copyright" content="十一星野"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="MyBatis 常见面试题总结javaguide.cn Guide 这是一则或许对你有用的小广告  面试专版 ：准备 Java 面试的小伙伴可以考虑面试专版：**《Java 面试指北 》** (质量非常高，专为面试打造，配合 JavaGuide 食用效果最佳)。 知识星球 ：技术专栏&#x2F;一对一提问&#x2F;简历修改&#x2F;求职指南&#x2F;面试打卡&#x2F;不定时福利，欢迎加入">
<meta property="og:type" content="article">
<meta property="og:title" content="MyBatis常见面试题总结">
<meta property="og:url" content="https://ko25891wan.gitlab.io/2024/01/01e1236339d4.html">
<meta property="og:site_name" content="小小程序员">
<meta property="og:description" content="MyBatis 常见面试题总结javaguide.cn Guide 这是一则或许对你有用的小广告  面试专版 ：准备 Java 面试的小伙伴可以考虑面试专版：**《Java 面试指北 》** (质量非常高，专为面试打造，配合 JavaGuide 食用效果最佳)。 知识星球 ：技术专栏&#x2F;一对一提问&#x2F;简历修改&#x2F;求职指南&#x2F;面试打卡&#x2F;不定时福利，欢迎加入">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://qiniu.ko25891wan.top/%E6%97%A5%E8%AE%B0%E8%BD%AF%E4%BB%B6/%E5%A4%B4%E5%83%8F/%E7%81%B0%E5%A4%AA%E7%8B%BC.png">
<meta property="article:published_time" content="2024-01-31T06:55:50.000Z">
<meta property="article:modified_time" content="2024-02-03T02:59:10.084Z">
<meta property="article:author" content="十一星野">
<meta property="article:tag" content="宅男,热血">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://qiniu.ko25891wan.top/%E6%97%A5%E8%AE%B0%E8%BD%AF%E4%BB%B6/%E5%A4%B4%E5%83%8F/%E7%81%B0%E5%A4%AA%E7%8B%BC.png"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="https://ko25891wan.gitlab.io/2024/01/01e1236339d4.html"><link rel="preconnect" href="//fastly.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/6.5.1/css/all.min.css"><link rel="stylesheet" href="https://cdn.staticfile.org/fancyapps-ui/5.0.32/fancybox/fancybox.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = {
  root: '/',
  algolia: undefined,
  localSearch: {"path":"/search.xml","preload":false,"top_n_per_article":1,"unescape":false,"languages":{"hits_empty":"找不到您查询的内容：${query}","hits_stats":"共找到 ${hits} 篇文章"}},
  translate: {"defaultEncoding":1,"translateDelay":0,"msgToTraditionalChinese":"繁","msgToSimplifiedChinese":"简"},
  noticeOutdate: undefined,
  highlight: {"plugin":"highlight.js","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":200},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: true,
    post: true
  },
  runtime: '',
  dateSuffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  infinitegrid: {
    js: 'https://cdn.staticfile.org/egjs-infinitegrid/4.11.0/infinitegrid.min.js',
    buttonText: '加载更多'
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isAnchor: false,
  percent: {
    toc: true,
    rightside: true,
  },
  autoDarkmode: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: '分类: 面试',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2024-02-03 10:59:10'
}</script><script>(win=>{
      win.saveToLocal = {
        set: (key, value, ttl) => {
          if (ttl === 0) return
          const now = Date.now()
          const expiry = now + ttl * 86400000
          const item = {
            value,
            expiry
          }
          localStorage.setItem(key, JSON.stringify(item))
        },
      
        get: key => {
          const itemStr = localStorage.getItem(key)
      
          if (!itemStr) {
            return undefined
          }
          const item = JSON.parse(itemStr)
          const now = Date.now()
      
          if (now > item.expiry) {
            localStorage.removeItem(key)
            return undefined
          }
          return item.value
        }
      }
    
      win.getScript = (url, attr = {}) => new Promise((resolve, reject) => {
        const script = document.createElement('script')
        script.src = url
        script.async = true
        script.onerror = reject
        script.onload = script.onreadystatechange = function() {
          const loadState = this.readyState
          if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
          script.onload = script.onreadystatechange = null
          resolve()
        }

        Object.keys(attr).forEach(key => {
          script.setAttribute(key, attr[key])
        })

        document.head.appendChild(script)
      })
    
      win.getCSS = (url, id = false) => new Promise((resolve, reject) => {
        const link = document.createElement('link')
        link.rel = 'stylesheet'
        link.href = url
        if (id) link.id = id
        link.onerror = reject
        link.onload = link.onreadystatechange = function() {
          const loadState = this.readyState
          if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
          link.onload = link.onreadystatechange = null
          resolve()
        }
        document.head.appendChild(link)
      })
    
      win.activateDarkMode = () => {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = () => {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
        if (t === 'dark') activateDarkMode()
        else if (t === 'light') activateLightMode()
      
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
      const detectApple = () => {
        if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
          document.documentElement.classList.add('apple')
        }
      }
      detectApple()
    })(window)</script><meta name="generator" content="Hexo 6.3.0"></head><body><div id="loading-box"><div class="loading-left-bg"></div><div class="loading-right-bg"></div><div class="spinner-box"><div class="configure-border-1"><div class="configure-core"></div></div><div class="configure-border-2"><div class="configure-core"></div></div><div class="loading-word">加载中...</div></div></div><script>(()=>{
  const $loadingBox = document.getElementById('loading-box')
  const $body = document.body
  const preloader = {
    endLoading: () => {
      $body.style.overflow = ''
      $loadingBox.classList.add('loaded')
    },
    initLoading: () => {
      $body.style.overflow = 'hidden'
      $loadingBox.classList.remove('loaded')
    }
  }

  preloader.initLoading()
  window.addEventListener('load',() => { preloader.endLoading() })

  if (false) {
    document.addEventListener('pjax:send', () => { preloader.initLoading() })
    document.addEventListener('pjax:complete', () => { preloader.endLoading() })
  }
})()</script><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://qiniu.ko25891wan.top/%E6%97%A5%E8%AE%B0%E8%BD%AF%E4%BB%B6/%E5%A4%B4%E5%83%8F/%E7%81%B0%E5%A4%AA%E7%8B%BC.png" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">120</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">4</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">22</div></a></div><hr class="custom-hr"/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fa fa-heartbeat"></i><span> 清单</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li><li><a class="site-page child" href="/Gallery/"><i class="fa-fw fas fa-images"></i><span> 照片</span></a></li><li><a class="site-page child" href="/movies/"><i class="fa-fw fas fa-video"></i><span> 电影</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-tools"></i><span> 工具</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/md_editor/"><i class="fa-fw fas fa-pen"></i><span> MDEditor_my</span></a></li></ul></div></div></div></div><div class="post" id="body-wrap"><header class="not-top-img" id="page-header"><nav id="nav"><span id="blog-info"><a href="/" title="小小程序员"><span class="site-name">小小程序员</span></a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search" href="javascript:void(0);"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fa fa-heartbeat"></i><span> 清单</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li><li><a class="site-page child" href="/Gallery/"><i class="fa-fw fas fa-images"></i><span> 照片</span></a></li><li><a class="site-page child" href="/movies/"><i class="fa-fw fas fa-video"></i><span> 电影</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-tools"></i><span> 工具</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/md_editor/"><i class="fa-fw fas fa-pen"></i><span> MDEditor_my</span></a></li></ul></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav></header><main class="layout" id="content-inner"><div id="post"><div id="post-info"><h1 class="post-title">MyBatis常见面试题总结</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2024-01-31T06:55:50.000Z" title="发表于 2024-01-31 14:55:50">2024-01-31</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2024-02-03T02:59:10.084Z" title="更新于 2024-02-03 10:59:10">2024-02-03</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/%E9%9D%A2%E8%AF%95/">面试</a><i class="fas fa-angle-right post-meta-separator"></i><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/%E9%9D%A2%E8%AF%95/%E9%9D%A2%E8%AF%95%E5%AE%9D%E5%85%B8/">面试宝典</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">4.4k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>15分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="MyBatis常见面试题总结"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div><article class="post-content" id="article-container"><h1 id="MyBatis-常见面试题总结"><a href="#MyBatis-常见面试题总结" class="headerlink" title="MyBatis 常见面试题总结"></a>MyBatis 常见面试题总结</h1><p><a target="_blank" rel="noopener" href="https://javaguide.cn/system-design/framework/mybatis/mybatis-interview.html">javaguide.cn</a> Guide</p>
<p>这是一则或许对你有用的小广告</p>
<ul>
<li><strong>面试专版</strong> ：准备 Java 面试的小伙伴可以考虑面试专版：**<a target="_blank" rel="noopener" href="https://javaguide.cn/zhuanlan/java-mian-shi-zhi-bei.html">《Java 面试指北 》</a>** (质量非常高，专为面试打造，配合 JavaGuide 食用效果最佳)。</li>
<li><strong>知识星球</strong> ：技术专栏&#x2F;一对一提问&#x2F;简历修改&#x2F;求职指南&#x2F;面试打卡&#x2F;不定时福利，欢迎加入 **<a target="_blank" rel="noopener" href="https://javaguide.cn/about-the-author/zhishixingqiu-two-years.html">JavaGuide 官方知识星球</a>**。</li>
</ul>
<blockquote>
<p>本篇文章由 JavaGuide 收集自网络，原出处不明。</p>
<p>比起这些枯燥的面试题，我更建议你看看文末推荐的 MyBatis 优质好文。</p>
</blockquote>
<h3 id="和-的区别是什么？"><a href="#和-的区别是什么？" class="headerlink" title="#{} 和 ${} 的区别是什么？"></a>#{} 和 ${} 的区别是什么？</h3><p>注：这道题是面试官面试我同事的。</p>
<p>答：</p>
<ul>
<li><p><code>$&#123;&#125;</code> 是 Properties 文件中的变量占位符，它可以用于标签属性值和 sql 内部，属于原样文本替换，可以替换任意内容，比如${driver}会被原样替换为 <code>com.mysql.jdbc. Driver</code>。<br>一个实例：根据参数按任意字段排序：</p>
<p>  select * from users order by ${orderCols}</p>
</li>
</ul>
<p><code>orderCols</code> 可以是 <code>name</code>、<code>name desc</code>、<code>name,sex asc</code> 等，实现灵活的排序。</p>
<ul>
<li><code>#&#123;&#125;</code> 是 sql 的参数占位符，MyBatis 会将 sql 中的 <code>#&#123;&#125;</code> 替换为? 号，在 sql 执行前会使用 PreparedStatement 的参数设置方法，按序给 sql 的? 号占位符设置参数值，比如 ps.setInt (0, parameterValue)，<code>#&#123;item.name&#125;</code> 的取值方式为使用反射从参数对象中获取 item 对象的 name 属性值，相当于 <code>param.getItem().getName()</code>。</li>
</ul>
<h3 id="xml-映射文件中，除了常见的-select、insert、update、delete-标签之外，还有哪些标签？"><a href="#xml-映射文件中，除了常见的-select、insert、update、delete-标签之外，还有哪些标签？" class="headerlink" title="xml 映射文件中，除了常见的 select、insert、update、delete 标签之外，还有哪些标签？"></a>xml 映射文件中，除了常见的 select、insert、update、delete 标签之外，还有哪些标签？</h3><p>注：这道题是京东面试官面试我时问的。</p>
<p>答：还有很多其他的标签， <code>&lt;resultMap&gt;</code>、 <code>&lt;parameterMap&gt;</code>、 <code>&lt;sql&gt;</code>、 <code>&lt;include&gt;</code>、 <code>&lt;selectKey&gt;</code> ，加上动态 sql 的 9 个标签， <code>trim|where|set|foreach|if|choose|when|otherwise|bind</code> 等，其中 <code>&lt;sql&gt;</code> 为 sql 片段标签，通过 <code>&lt;include&gt;</code> 标签引入 sql 片段， <code>&lt;selectKey&gt;</code> 为不支持自增的主键生成策略标签。</p>
<h3 id="Dao-接口的工作原理是什么？Dao-接口里的方法，参数不同时，方法能重载吗？"><a href="#Dao-接口的工作原理是什么？Dao-接口里的方法，参数不同时，方法能重载吗？" class="headerlink" title="Dao 接口的工作原理是什么？Dao 接口里的方法，参数不同时，方法能重载吗？"></a>Dao 接口的工作原理是什么？Dao 接口里的方法，参数不同时，方法能重载吗？</h3><p>注：这道题也是京东面试官面试我被问的。</p>
<p>答：最佳实践中，通常一个 xml 映射文件，都会写一个 Dao 接口与之对应。Dao 接口就是人们常说的 <code>Mapper</code> 接口，接口的全限名，就是映射文件中的 namespace 的值，接口的方法名，就是映射文件中 <code>MappedStatement</code> 的 id 值，接口方法内的参数，就是传递给 sql 的参数。 <code>Mapper</code> 接口是没有实现类的，当调用接口方法时，接口全限名+方法名拼接字符串作为 key 值，可唯一定位一个 <code>MappedStatement</code> ，举例：<code>com.mybatis3.mappers. StudentDao.findStudentById</code> ，可以唯一找到 namespace 为 <code>com.mybatis3.mappers. StudentDao</code> 下面 <code>id = findStudentById</code> 的 <code>MappedStatement</code> 。在 MyBatis 中，每一个 <code>&lt;select&gt;</code>、 <code>&lt;insert&gt;</code>、 <code>&lt;update&gt;</code>、 <code>&lt;delete&gt;</code> 标签，都会被解析为一个 <code>MappedStatement</code> 对象。</p>
<p>Dao 接口里的方法，是不能重载的，因为是全限名+方法名的保存和寻找策略。</p>
<p>Dao 接口里的方法可以重载，但是 Mybatis 的 xml 里面的 ID 不允许重复。</p>
<p>Mybatis 版本 3.3.0，亲测如下：</p>
<pre><code>/**
 * Mapper接口里面方法重载
 */
public interface StuMapper &#123;

 List&lt;Student&gt; getAllStu();

 List&lt;Student&gt; getAllStu(@Param(&quot;id&quot;) Integer id);
&#125;
</code></pre>
<p>然后在 <code>StuMapper.xml</code> 中利用 Mybatis 的动态 sql 就可以实现。</p>
<pre><code>&lt;select id=&quot;getAllStu&quot; resultType=&quot;com.pojo.Student&quot;&gt;
  select * from student
  &lt;where&gt;
    &lt;if test=&quot;id != null&quot;&gt;
      id = #&#123;id&#125;
    &lt;/if&gt;
  &lt;/where&gt;
&lt;/select&gt;
</code></pre>
<p>能正常运行，并能得到相应的结果，这样就实现了在 Dao 接口中写重载方法。</p>
<p><strong>Mybatis 的 Dao 接口可以有多个重载方法，但是多个接口对应的映射必须只有一个，否则启动会报错。</strong></p>
<p>相关 issue：<a target="_blank" rel="noopener" href="https://github.com/Snailclimb/JavaGuide/issues/1122">更正：Dao 接口里的方法可以重载，但是 Mybatis 的 xml 里面的 ID 不允许重复！open in new window</a>。</p>
<p>Dao 接口的工作原理是 JDK 动态代理，MyBatis 运行时会使用 JDK 动态代理为 Dao 接口生成代理 proxy 对象，代理对象 proxy 会拦截接口方法，转而执行 <code>MappedStatement</code> 所代表的 sql，然后将 sql 执行结果返回。</p>
<p><strong>补充</strong>：</p>
<p>Dao 接口方法可以重载，但是需要满足以下条件：</p>
<ol>
<li>仅有一个无参方法和一个有参方法</li>
<li>多个有参方法时，参数数量必须一致。且使用相同的 <code>@Param</code> ，或者使用 <code>param1</code> 这种</li>
</ol>
<p><strong>测试如下</strong>：</p>
<p><code>PersonDao.java</code></p>
<pre><code>Person queryById();

Person queryById(@Param(&quot;id&quot;) Long id);

Person queryById(@Param(&quot;id&quot;) Long id, @Param(&quot;name&quot;) String name);
</code></pre>
<p><code>PersonMapper.xml</code></p>
<pre><code>&lt;select id=&quot;queryById&quot; resultMap=&quot;PersonMap&quot;&gt;
    select
      id, name, age, address
    from person
    &lt;where&gt;
        &lt;if test=&quot;id != null&quot;&gt;
            id = #&#123;id&#125;
        &lt;/if&gt;
        &lt;if test=&quot;name != null and name != &#39;&#39;&quot;&gt;
            name = #&#123;name&#125;
        &lt;/if&gt;
    &lt;/where&gt;
    limit 1
&lt;/select&gt;
</code></pre>
<p><code>org.apache.ibatis.scripting.xmltags. DynamicContext. ContextAccessor#getProperty</code> 方法用于获取 <code>&lt;if&gt;</code> 标签中的条件值</p>
<pre><code>public Object getProperty(Map context, Object target, Object name) &#123;
  Map map = (Map) target;

  Object result = map.get(name);
  if (map.containsKey(name) || result != null) &#123;
    return result;
  &#125;

  Object parameterObject = map.get(PARAMETER_OBJECT_KEY);
  if (parameterObject instanceof Map) &#123;
    return ((Map)parameterObject).get(name);
  &#125;

  return null;
&#125;
</code></pre>
<p><code>parameterObject</code> 为 map，存放的是 Dao 接口中参数相关信息。</p>
<p><code>((Map)parameterObject).get(name)</code> 方法如下</p>
<pre><code>public V get(Object key) &#123;
  if (!super.containsKey(key)) &#123;
    throw new BindingException(&quot;Parameter &#39;&quot; + key + &quot;&#39; not found. Available parameters are &quot; + keySet());
  &#125;
  return super.get(key);
&#125;
</code></pre>
<ol>
<li><code>queryById()</code> 方法执行时，<code>parameterObject</code> 为 null，<code>getProperty</code> 方法返回 null 值，<code>&lt;if&gt;</code> 标签获取的所有条件值都为 null，所有条件不成立，动态 sql 可以正常执行。</li>
<li><code>queryById(1L)</code> 方法执行时，<code>parameterObject</code> 为 map，包含了 <code>id</code> 和 <code>param1</code> 两个 key 值。当获取 <code>&lt;if&gt;</code> 标签中 <code>name</code> 的属性值时，进入 <code>((Map)parameterObject).get(name)</code> 方法中，map 中 key 不包含 <code>name</code>，所以抛出异常。</li>
<li><code>queryById(1L,&quot;1&quot;)</code> 方法执行时，<code>parameterObject</code> 中包含 <code>id</code>, <code>param1</code>, <code>name</code>, <code>param2</code> 四个 key 值，<code>id</code> 和 <code>name</code> 属性都可以获取到，动态 sql 正常执行。</li>
</ol>
<h3 id="MyBatis-是如何进行分页的？分页插件的原理是什么？"><a href="#MyBatis-是如何进行分页的？分页插件的原理是什么？" class="headerlink" title="MyBatis 是如何进行分页的？分页插件的原理是什么？"></a>MyBatis 是如何进行分页的？分页插件的原理是什么？</h3><p>注：我出的。</p>
<p>答：**(1)** MyBatis 使用 RowBounds 对象进行分页，它是针对 ResultSet 结果集执行的内存分页，而非物理分页；**(2)** 可以在 sql 内直接书写带有物理分页的参数来完成物理分页功能，**(3)** 也可以使用分页插件来完成物理分页。</p>
<p>分页插件的基本原理是使用 MyBatis 提供的插件接口，实现自定义插件，在插件的拦截方法内拦截待执行的 sql，然后重写 sql，根据 dialect 方言，添加对应的物理分页语句和物理分页参数。</p>
<p>举例：<code>select _ from student</code> ，拦截 sql 后重写为：<code>select t._ from （select \* from student）t limit 0，10</code></p>
<h3 id="简述-MyBatis-的插件运行原理，以及如何编写一个插件"><a href="#简述-MyBatis-的插件运行原理，以及如何编写一个插件" class="headerlink" title="简述 MyBatis 的插件运行原理，以及如何编写一个插件"></a>简述 MyBatis 的插件运行原理，以及如何编写一个插件</h3><p>注：我出的。</p>
<p>答：MyBatis 仅可以编写针对 <code>ParameterHandler</code>、 <code>ResultSetHandler</code>、 <code>StatementHandler</code>、 <code>Executor</code> 这 4 种接口的插件，MyBatis 使用 JDK 的动态代理，为需要拦截的接口生成代理对象以实现接口方法拦截功能，每当执行这 4 种接口对象的方法时，就会进入拦截方法，具体就是 <code>InvocationHandler</code> 的 <code>invoke()</code> 方法，当然，只会拦截那些你指定需要拦截的方法。</p>
<p>实现 MyBatis 的 <code>Interceptor</code> 接口并复写 <code>intercept()</code> 方法，然后在给插件编写注解，指定要拦截哪一个接口的哪些方法即可，记住，别忘了在配置文件中配置你编写的插件。</p>
<h3 id="MyBatis-执行批量插入，能返回数据库主键列表吗？"><a href="#MyBatis-执行批量插入，能返回数据库主键列表吗？" class="headerlink" title="MyBatis 执行批量插入，能返回数据库主键列表吗？"></a>MyBatis 执行批量插入，能返回数据库主键列表吗？</h3><p>注：我出的。</p>
<p>答：能，JDBC 都能，MyBatis 当然也能。</p>
<h3 id="MyBatis-动态-sql-是做什么的？都有哪些动态-sql？能简述一下动态-sql-的执行原理不？"><a href="#MyBatis-动态-sql-是做什么的？都有哪些动态-sql？能简述一下动态-sql-的执行原理不？" class="headerlink" title="MyBatis 动态 sql 是做什么的？都有哪些动态 sql？能简述一下动态 sql 的执行原理不？"></a>MyBatis 动态 sql 是做什么的？都有哪些动态 sql？能简述一下动态 sql 的执行原理不？</h3><p>注：我出的。</p>
<p>答：MyBatis 动态 sql 可以让我们在 xml 映射文件内，以标签的形式编写动态 sql，完成逻辑判断和动态拼接 sql 的功能。其执行原理为，使用 OGNL 从 sql 参数对象中计算表达式的值，根据表达式的值动态拼接 sql，以此来完成动态 sql 的功能。</p>
<p>MyBatis 提供了 9 种动态 sql 标签:</p>
<ul>
<li><code>&lt;if&gt;&lt;/if&gt;</code></li>
<li><code>&lt;where&gt;&lt;/where&gt;(trim,set)</code></li>
<li><code>&lt;choose&gt;&lt;/choose&gt;（when, otherwise）</code></li>
<li><code>&lt;foreach&gt;&lt;/foreach&gt;</code></li>
<li><code>&lt;bind/&gt;</code></li>
</ul>
<p>关于 MyBatis 动态 SQL 的详细介绍，请看这篇文章：<a target="_blank" rel="noopener" href="https://segmentfault.com/a/1190000039335704">Mybatis 系列全解（八）：Mybatis 的 9 大动态 SQL 标签你知道几个？open in new window</a> 。</p>
<p>关于这些动态 SQL 的具体使用方法，请看这篇文章：<a target="_blank" rel="noopener" href="https://cloud.tencent.com/developer/article/1943349">Mybatis【13】– Mybatis 动态 sql 标签怎么使用？open in new window</a></p>
<h3 id="MyBatis-是如何将-sql-执行结果封装为目标对象并返回的？都有哪些映射形式？"><a href="#MyBatis-是如何将-sql-执行结果封装为目标对象并返回的？都有哪些映射形式？" class="headerlink" title="MyBatis 是如何将 sql 执行结果封装为目标对象并返回的？都有哪些映射形式？"></a>MyBatis 是如何将 sql 执行结果封装为目标对象并返回的？都有哪些映射形式？</h3><p>注：我出的。</p>
<p>答：第一种是使用 <code>&lt;resultMap&gt;</code> 标签，逐一定义列名和对象属性名之间的映射关系。第二种是使用 sql 列的别名功能，将列别名书写为对象属性名，比如 T_NAME AS NAME，对象属性名一般是 name，小写，但是列名不区分大小写，MyBatis 会忽略列名大小写，智能找到与之对应对象属性名，你甚至可以写成 T_NAME AS NaMe，MyBatis 一样可以正常工作。</p>
<p>有了列名与属性名的映射关系后，MyBatis 通过反射创建对象，同时使用反射给对象的属性逐一赋值并返回，那些找不到映射关系的属性，是无法完成赋值的。</p>
<h3 id="MyBatis-能执行一对一、一对多的关联查询吗？都有哪些实现方式，以及它们之间的区别"><a href="#MyBatis-能执行一对一、一对多的关联查询吗？都有哪些实现方式，以及它们之间的区别" class="headerlink" title="MyBatis 能执行一对一、一对多的关联查询吗？都有哪些实现方式，以及它们之间的区别"></a>MyBatis 能执行一对一、一对多的关联查询吗？都有哪些实现方式，以及它们之间的区别</h3><p>注：我出的。</p>
<p>答：能，MyBatis 不仅可以执行一对一、一对多的关联查询，还可以执行多对一，多对多的关联查询，多对一查询，其实就是一对一查询，只需要把 <code>selectOne()</code> 修改为 <code>selectList()</code> 即可；多对多查询，其实就是一对多查询，只需要把 <code>selectOne()</code> 修改为 <code>selectList()</code> 即可。</p>
<p>关联对象查询，有两种实现方式，一种是单独发送一个 sql 去查询关联对象，赋给主对象，然后返回主对象。另一种是使用嵌套查询，嵌套查询的含义为使用 join 查询，一部分列是 A 对象的属性值，另外一部分列是关联对象 B 的属性值，好处是只发一个 sql 查询，就可以把主对象和其关联对象查出来。</p>
<p>那么问题来了，join 查询出来 100 条记录，如何确定主对象是 5 个，而不是 100 个？其去重复的原理是 <code>&lt;resultMap&gt;</code> 标签内的 <code>&lt;id&gt;</code> 子标签，指定了唯一确定一条记录的 id 列，MyBatis 根据 <code>&lt;id&gt;</code> 列值来完成 100 条记录的去重复功能， <code>&lt;id&gt;</code> 可以有多个，代表了联合主键的语意。</p>
<p>同样主对象的关联对象，也是根据这个原理去重复的，尽管一般情况下，只有主对象会有重复记录，关联对象一般不会重复。</p>
<p>举例：下面 join 查询出来 6 条记录，一、二列是 Teacher 对象列，第三列为 Student 对象列，MyBatis 去重复处理后，结果为 1 个老师 6 个学生，而不是 6 个老师 6 个学生。</p>
<table>
<thead>
<tr>
<th>t_id</th>
<th>t_name</th>
<th>s_id</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>teacher</td>
<td>38</td>
</tr>
<tr>
<td>1</td>
<td>teacher</td>
<td>39</td>
</tr>
<tr>
<td>1</td>
<td>teacher</td>
<td>40</td>
</tr>
<tr>
<td>1</td>
<td>teacher</td>
<td>41</td>
</tr>
<tr>
<td>1</td>
<td>teacher</td>
<td>42</td>
</tr>
<tr>
<td>1</td>
<td>teacher</td>
<td>43</td>
</tr>
</tbody></table>
<h3 id="MyBatis-是否支持延迟加载？如果支持，它的实现原理是什么？"><a href="#MyBatis-是否支持延迟加载？如果支持，它的实现原理是什么？" class="headerlink" title="MyBatis 是否支持延迟加载？如果支持，它的实现原理是什么？"></a>MyBatis 是否支持延迟加载？如果支持，它的实现原理是什么？</h3><p>注：我出的。</p>
<p>答：MyBatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载，association 指的就是一对一，collection 指的就是一对多查询。在 MyBatis 配置文件中，可以配置是否启用延迟加载 <code>lazyLoadingEnabled=true|false。</code></p>
<p>它的原理是，使用 <code>CGLIB</code> 创建目标对象的代理对象，当调用目标方法时，进入拦截器方法，比如调用 <code>a.getB().getName()</code> ，拦截器 <code>invoke()</code> 方法发现 <code>a.getB()</code> 是 null 值，那么就会单独发送事先保存好的查询关联 B 对象的 sql，把 B 查询上来，然后调用 a.setB (b)，于是 a 的对象 b 属性就有值了，接着完成 <code>a.getB().getName()</code> 方法的调用。这就是延迟加载的基本原理。</p>
<p>当然了，不光是 MyBatis，几乎所有的包括 Hibernate，支持延迟加载的原理都是一样的。</p>
<h3 id="MyBatis-的-xml-映射文件中，不同的-xml-映射文件，id-是否可以重复？"><a href="#MyBatis-的-xml-映射文件中，不同的-xml-映射文件，id-是否可以重复？" class="headerlink" title="MyBatis 的 xml 映射文件中，不同的 xml 映射文件，id 是否可以重复？"></a>MyBatis 的 xml 映射文件中，不同的 xml 映射文件，id 是否可以重复？</h3><p>注：我出的。</p>
<p>答：不同的 xml 映射文件，如果配置了 namespace，那么 id 可以重复；如果没有配置 namespace，那么 id 不能重复；毕竟 namespace 不是必须的，只是最佳实践而已。</p>
<p>原因就是 namespace+id 是作为 <code>Map&lt;String, MappedStatement&gt;</code> 的 key 使用的，如果没有 namespace，就剩下 id，那么，id 重复会导致数据互相覆盖。有了 namespace，自然 id 就可以重复，namespace 不同，namespace+id 自然也就不同。</p>
<h3 id="MyBatis-中如何执行批处理？"><a href="#MyBatis-中如何执行批处理？" class="headerlink" title="MyBatis 中如何执行批处理？"></a>MyBatis 中如何执行批处理？</h3><p>注：我出的。</p>
<p>答：使用 <code>BatchExecutor</code> 完成批处理。</p>
<h3 id="MyBatis-都有哪些-Executor-执行器？它们之间的区别是什么？"><a href="#MyBatis-都有哪些-Executor-执行器？它们之间的区别是什么？" class="headerlink" title="MyBatis 都有哪些 Executor 执行器？它们之间的区别是什么？"></a>MyBatis 都有哪些 Executor 执行器？它们之间的区别是什么？</h3><p>注：我出的</p>
<p>答：MyBatis 有三种基本的 <code>Executor</code> 执行器：</p>
<ul>
<li><strong><code>SimpleExecutor</code>：</strong> 每执行一次 update 或 select，就开启一个 Statement 对象，用完立刻关闭 Statement 对象。</li>
<li><strong><code>ReuseExecutor</code>：</strong> 执行 update 或 select，以 sql 作为 key 查找 Statement 对象，存在就使用，不存在就创建，用完后，不关闭 Statement 对象，而是放置于 Map&lt;String, Statement&gt;内，供下一次使用。简言之，就是重复使用 Statement 对象。</li>
<li>**<code>BatchExecutor</code>**：执行 update（没有 select，JDBC 批处理不支持 select），将所有 sql 都添加到批处理中（addBatch ()），等待统一执行（executeBatch ()），它缓存了多个 Statement 对象，每个 Statement 对象都是 addBatch ()完毕后，等待逐一执行 executeBatch ()批处理。与 JDBC 批处理相同。</li>
</ul>
<p>作用范围：<code>Executor</code> 的这些特点，都严格限制在 SqlSession 生命周期范围内。</p>
<h3 id="MyBatis-中如何指定使用哪一种-Executor-执行器？"><a href="#MyBatis-中如何指定使用哪一种-Executor-执行器？" class="headerlink" title="MyBatis 中如何指定使用哪一种 Executor 执行器？"></a>MyBatis 中如何指定使用哪一种 Executor 执行器？</h3><p>注：我出的</p>
<p>答：在 MyBatis 配置文件中，可以指定默认的 <code>ExecutorType</code> 执行器类型，也可以手动给 <code>DefaultSqlSessionFactory</code> 的创建 SqlSession 的方法传递 <code>ExecutorType</code> 类型参数。</p>
<h3 id="MyBatis-是否可以映射-Enum-枚举类？"><a href="#MyBatis-是否可以映射-Enum-枚举类？" class="headerlink" title="MyBatis 是否可以映射 Enum 枚举类？"></a>MyBatis 是否可以映射 Enum 枚举类？</h3><p>注：我出的</p>
<p>答：MyBatis 可以映射枚举类，不单可以映射枚举类，MyBatis 可以映射任何对象到表的一列上。映射方式为自定义一个 <code>TypeHandler</code> ，实现 <code>TypeHandler</code> 的 <code>setParameter()</code> 和 <code>getResult()</code> 接口方法。 <code>TypeHandler</code> 有两个作用：</p>
<ul>
<li>一是完成从 javaType 至 jdbcType 的转换；</li>
<li>二是完成 jdbcType 至 javaType 的转换，体现为 <code>setParameter()</code> 和 <code>getResult()</code> 两个方法，分别代表设置 sql 问号占位符参数和获取列查询结果。</li>
</ul>
<h3 id="MyBatis-映射文件中，如果-A-标签通过-include-引用了-B-标签的内容，请问，B-标签能否定义在-A-标签的后面，还是说必须定义在-A-标签的前面？"><a href="#MyBatis-映射文件中，如果-A-标签通过-include-引用了-B-标签的内容，请问，B-标签能否定义在-A-标签的后面，还是说必须定义在-A-标签的前面？" class="headerlink" title="MyBatis 映射文件中，如果 A 标签通过 include 引用了 B 标签的内容，请问，B 标签能否定义在 A 标签的后面，还是说必须定义在 A 标签的前面？"></a>MyBatis 映射文件中，如果 A 标签通过 include 引用了 B 标签的内容，请问，B 标签能否定义在 A 标签的后面，还是说必须定义在 A 标签的前面？</h3><p>注：我出的</p>
<p>答：虽然 MyBatis 解析 xml 映射文件是按照顺序解析的，但是，被引用的 B 标签依然可以定义在任何地方，MyBatis 都可以正确识别。</p>
<p>原理是，MyBatis 解析 A 标签，发现 A 标签引用了 B 标签，但是 B 标签尚未解析到，尚不存在，此时，MyBatis 会将 A 标签标记为未解析状态，然后继续解析余下的标签，包含 B 标签，待所有标签解析完毕，MyBatis 会重新解析那些被标记为未解析的标签，此时再解析 A 标签时，B 标签已经存在，A 标签也就可以正常解析完成了。</p>
<h3 id="简述-MyBatis-的-xml-映射文件和-MyBatis-内部数据结构之间的映射关系？"><a href="#简述-MyBatis-的-xml-映射文件和-MyBatis-内部数据结构之间的映射关系？" class="headerlink" title="简述 MyBatis 的 xml 映射文件和 MyBatis 内部数据结构之间的映射关系？"></a>简述 MyBatis 的 xml 映射文件和 MyBatis 内部数据结构之间的映射关系？</h3><p>注：我出的</p>
<p>答：MyBatis 将所有 xml 配置信息都封装到 All-In-One 重量级对象 Configuration 内部。在 xml 映射文件中， <code>&lt;parameterMap&gt;</code> 标签会被解析为 <code>ParameterMap</code> 对象，其每个子元素会被解析为 ParameterMapping 对象。 <code>&lt;resultMap&gt;</code> 标签会被解析为 <code>ResultMap</code> 对象，其每个子元素会被解析为 <code>ResultMapping</code> 对象。每一个 <code>&lt;select&gt;、&lt;insert&gt;、&lt;update&gt;、&lt;delete&gt;</code> 标签均会被解析为 <code>MappedStatement</code> 对象，标签内的 sql 会被解析为 BoundSql 对象。</p>
<h3 id="为什么说-MyBatis-是半自动-ORM-映射工具？它与全自动的区别在哪里？"><a href="#为什么说-MyBatis-是半自动-ORM-映射工具？它与全自动的区别在哪里？" class="headerlink" title="为什么说 MyBatis 是半自动 ORM 映射工具？它与全自动的区别在哪里？"></a>为什么说 MyBatis 是半自动 ORM 映射工具？它与全自动的区别在哪里？</h3><p>注：我出的</p>
<p>答：Hibernate 属于全自动 ORM 映射工具，使用 Hibernate 查询关联对象或者关联集合对象时，可以根据对象关系模型直接获取，所以它是全自动的。而 MyBatis 在查询关联对象或关联集合对象时，需要手动编写 sql 来完成，所以，称之为半自动 ORM 映射工具。</p>
<p>面试题看似都很简单，但是想要能正确回答上来，必定是研究过源码且深入的人，而不是仅会使用的人或者用的很熟的人，以上所有面试题及其答案所涉及的内容，在我的 MyBatis 系列博客中都有详细讲解和原理分析。<br><img src="https://qiniu.ko25891wan.top/%E6%97%A5%E8%AE%B0%E8%BD%AF%E4%BB%B6/obsition/2024-02-03_10:59:06_c4ca4238a0b923820dcc509a6f75849b" alt="JavaGuide 官方公众号"> JavaGuide 官方公众号</p>
<h3 id="文章推荐"><a href="#文章推荐" class="headerlink" title="文章推荐"></a>文章推荐</h3><ul>
<li><a target="_blank" rel="noopener" href="https://juejin.cn/post/7273516671574687759">2W 字全面剖析 Mybatis 中的 9 种设计模式open in new window</a></li>
<li><a target="_blank" rel="noopener" href="https://mp.weixin.qq.com/s/WUEAdFDwZsZ4EKO8ix0ijg">从零开始实现一个 MyBatis 加解密插件open in new window</a></li>
<li><a target="_blank" rel="noopener" href="https://juejin.cn/post/7051910683264286750">MyBatis 最全使用指南open in new window</a></li>
<li><a target="_blank" rel="noopener" href="https://juejin.cn/post/7269390456530190376">脑洞打开！第一次看到这样使用 MyBatis 的，看得我一愣一愣的。open in new window</a></li>
<li><a target="_blank" rel="noopener" href="https://juejin.cn/post/7264921613551730722">MyBatis 居然也有并发问题open in new window</a></li>
</ul>
<p><a target="_blank" rel="noopener" href="https://cubox.pro/my/card?id=7152036058501221422">跳转到 Cubox 查看</a></p>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta"><i class="fas fa-circle-user fa-fw"></i>文章作者: </span><span class="post-copyright-info"><a href="https://ko25891wan.gitlab.io">十一星野</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta"><i class="fas fa-square-arrow-up-right fa-fw"></i>文章链接: </span><span class="post-copyright-info"><a href="https://ko25891wan.gitlab.io/2024/01/01e1236339d4.html">https://ko25891wan.gitlab.io/2024/01/01e1236339d4.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta"><i class="fas fa-circle-exclamation fa-fw"></i>版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://ko25891wan.gitlab.io" target="_blank">小小程序员</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"></div><div class="post_share"></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/2024/01/2cd154520a3c.html" title="MySQL常见面试题总结"><div class="cover" style="background: var(--default-bg-color)"></div><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">MySQL常见面试题总结</div></div></a></div><div class="next-post pull-right"><a href="/2024/01/fd03bd589630.html" title="Java集合常见面试题总结(下)"><div class="cover" style="background: var(--default-bg-color)"></div><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">Java集合常见面试题总结(下)</div></div></a></div></nav></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="https://qiniu.ko25891wan.top/%E6%97%A5%E8%AE%B0%E8%BD%AF%E4%BB%B6/%E5%A4%B4%E5%83%8F/%E7%81%B0%E5%A4%AA%E7%8B%BC.png" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">十一星野</div><div class="author-info__description">归途也还可爱</div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">120</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">4</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">22</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://gitlab.com/ko25891wan/ko25891wan.gitlab.io"><i class="fab fa-github"></i><span>关注我</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://gitlab.com/ko25891wan/ko25891wan.gitlab.io" target="_blank" title="Github"><i class="fab fa-github" style="color: #24292e;"></i></a><a class="social-icon" href="https://gitlab.com/ko25891wan/ko25891wan.gitlab.io" target="_blank" title="Gitlab"><i class="fab fa-gitlab" style="color: #24292e;"></i></a><a class="social-icon" href="mailto:ko25891wan@outlook.com" target="_blank" title="Email"><i class="fas fa-envelope" style="color: #4a7dbe;"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">This is my Blog</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#MyBatis-%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98%E6%80%BB%E7%BB%93"><span class="toc-number">1.</span> <span class="toc-text">MyBatis 常见面试题总结</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%92%8C-%E7%9A%84%E5%8C%BA%E5%88%AB%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F"><span class="toc-number">1.0.1.</span> <span class="toc-text">#{} 和 ${} 的区别是什么？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#xml-%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%E4%B8%AD%EF%BC%8C%E9%99%A4%E4%BA%86%E5%B8%B8%E8%A7%81%E7%9A%84-select%E3%80%81insert%E3%80%81update%E3%80%81delete-%E6%A0%87%E7%AD%BE%E4%B9%8B%E5%A4%96%EF%BC%8C%E8%BF%98%E6%9C%89%E5%93%AA%E4%BA%9B%E6%A0%87%E7%AD%BE%EF%BC%9F"><span class="toc-number">1.0.2.</span> <span class="toc-text">xml 映射文件中，除了常见的 select、insert、update、delete 标签之外，还有哪些标签？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Dao-%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9FDao-%E6%8E%A5%E5%8F%A3%E9%87%8C%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8F%82%E6%95%B0%E4%B8%8D%E5%90%8C%E6%97%B6%EF%BC%8C%E6%96%B9%E6%B3%95%E8%83%BD%E9%87%8D%E8%BD%BD%E5%90%97%EF%BC%9F"><span class="toc-number">1.0.3.</span> <span class="toc-text">Dao 接口的工作原理是什么？Dao 接口里的方法，参数不同时，方法能重载吗？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#MyBatis-%E6%98%AF%E5%A6%82%E4%BD%95%E8%BF%9B%E8%A1%8C%E5%88%86%E9%A1%B5%E7%9A%84%EF%BC%9F%E5%88%86%E9%A1%B5%E6%8F%92%E4%BB%B6%E7%9A%84%E5%8E%9F%E7%90%86%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F"><span class="toc-number">1.0.4.</span> <span class="toc-text">MyBatis 是如何进行分页的？分页插件的原理是什么？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%AE%80%E8%BF%B0-MyBatis-%E7%9A%84%E6%8F%92%E4%BB%B6%E8%BF%90%E8%A1%8C%E5%8E%9F%E7%90%86%EF%BC%8C%E4%BB%A5%E5%8F%8A%E5%A6%82%E4%BD%95%E7%BC%96%E5%86%99%E4%B8%80%E4%B8%AA%E6%8F%92%E4%BB%B6"><span class="toc-number">1.0.5.</span> <span class="toc-text">简述 MyBatis 的插件运行原理，以及如何编写一个插件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#MyBatis-%E6%89%A7%E8%A1%8C%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%EF%BC%8C%E8%83%BD%E8%BF%94%E5%9B%9E%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%BB%E9%94%AE%E5%88%97%E8%A1%A8%E5%90%97%EF%BC%9F"><span class="toc-number">1.0.6.</span> <span class="toc-text">MyBatis 执行批量插入，能返回数据库主键列表吗？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#MyBatis-%E5%8A%A8%E6%80%81-sql-%E6%98%AF%E5%81%9A%E4%BB%80%E4%B9%88%E7%9A%84%EF%BC%9F%E9%83%BD%E6%9C%89%E5%93%AA%E4%BA%9B%E5%8A%A8%E6%80%81-sql%EF%BC%9F%E8%83%BD%E7%AE%80%E8%BF%B0%E4%B8%80%E4%B8%8B%E5%8A%A8%E6%80%81-sql-%E7%9A%84%E6%89%A7%E8%A1%8C%E5%8E%9F%E7%90%86%E4%B8%8D%EF%BC%9F"><span class="toc-number">1.0.7.</span> <span class="toc-text">MyBatis 动态 sql 是做什么的？都有哪些动态 sql？能简述一下动态 sql 的执行原理不？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#MyBatis-%E6%98%AF%E5%A6%82%E4%BD%95%E5%B0%86-sql-%E6%89%A7%E8%A1%8C%E7%BB%93%E6%9E%9C%E5%B0%81%E8%A3%85%E4%B8%BA%E7%9B%AE%E6%A0%87%E5%AF%B9%E8%B1%A1%E5%B9%B6%E8%BF%94%E5%9B%9E%E7%9A%84%EF%BC%9F%E9%83%BD%E6%9C%89%E5%93%AA%E4%BA%9B%E6%98%A0%E5%B0%84%E5%BD%A2%E5%BC%8F%EF%BC%9F"><span class="toc-number">1.0.8.</span> <span class="toc-text">MyBatis 是如何将 sql 执行结果封装为目标对象并返回的？都有哪些映射形式？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#MyBatis-%E8%83%BD%E6%89%A7%E8%A1%8C%E4%B8%80%E5%AF%B9%E4%B8%80%E3%80%81%E4%B8%80%E5%AF%B9%E5%A4%9A%E7%9A%84%E5%85%B3%E8%81%94%E6%9F%A5%E8%AF%A2%E5%90%97%EF%BC%9F%E9%83%BD%E6%9C%89%E5%93%AA%E4%BA%9B%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F%EF%BC%8C%E4%BB%A5%E5%8F%8A%E5%AE%83%E4%BB%AC%E4%B9%8B%E9%97%B4%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-number">1.0.9.</span> <span class="toc-text">MyBatis 能执行一对一、一对多的关联查询吗？都有哪些实现方式，以及它们之间的区别</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#MyBatis-%E6%98%AF%E5%90%A6%E6%94%AF%E6%8C%81%E5%BB%B6%E8%BF%9F%E5%8A%A0%E8%BD%BD%EF%BC%9F%E5%A6%82%E6%9E%9C%E6%94%AF%E6%8C%81%EF%BC%8C%E5%AE%83%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F"><span class="toc-number">1.0.10.</span> <span class="toc-text">MyBatis 是否支持延迟加载？如果支持，它的实现原理是什么？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#MyBatis-%E7%9A%84-xml-%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%E4%B8%AD%EF%BC%8C%E4%B8%8D%E5%90%8C%E7%9A%84-xml-%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%EF%BC%8Cid-%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E9%87%8D%E5%A4%8D%EF%BC%9F"><span class="toc-number">1.0.11.</span> <span class="toc-text">MyBatis 的 xml 映射文件中，不同的 xml 映射文件，id 是否可以重复？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#MyBatis-%E4%B8%AD%E5%A6%82%E4%BD%95%E6%89%A7%E8%A1%8C%E6%89%B9%E5%A4%84%E7%90%86%EF%BC%9F"><span class="toc-number">1.0.12.</span> <span class="toc-text">MyBatis 中如何执行批处理？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#MyBatis-%E9%83%BD%E6%9C%89%E5%93%AA%E4%BA%9B-Executor-%E6%89%A7%E8%A1%8C%E5%99%A8%EF%BC%9F%E5%AE%83%E4%BB%AC%E4%B9%8B%E9%97%B4%E7%9A%84%E5%8C%BA%E5%88%AB%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F"><span class="toc-number">1.0.13.</span> <span class="toc-text">MyBatis 都有哪些 Executor 执行器？它们之间的区别是什么？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#MyBatis-%E4%B8%AD%E5%A6%82%E4%BD%95%E6%8C%87%E5%AE%9A%E4%BD%BF%E7%94%A8%E5%93%AA%E4%B8%80%E7%A7%8D-Executor-%E6%89%A7%E8%A1%8C%E5%99%A8%EF%BC%9F"><span class="toc-number">1.0.14.</span> <span class="toc-text">MyBatis 中如何指定使用哪一种 Executor 执行器？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#MyBatis-%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E6%98%A0%E5%B0%84-Enum-%E6%9E%9A%E4%B8%BE%E7%B1%BB%EF%BC%9F"><span class="toc-number">1.0.15.</span> <span class="toc-text">MyBatis 是否可以映射 Enum 枚举类？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#MyBatis-%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%E4%B8%AD%EF%BC%8C%E5%A6%82%E6%9E%9C-A-%E6%A0%87%E7%AD%BE%E9%80%9A%E8%BF%87-include-%E5%BC%95%E7%94%A8%E4%BA%86-B-%E6%A0%87%E7%AD%BE%E7%9A%84%E5%86%85%E5%AE%B9%EF%BC%8C%E8%AF%B7%E9%97%AE%EF%BC%8CB-%E6%A0%87%E7%AD%BE%E8%83%BD%E5%90%A6%E5%AE%9A%E4%B9%89%E5%9C%A8-A-%E6%A0%87%E7%AD%BE%E7%9A%84%E5%90%8E%E9%9D%A2%EF%BC%8C%E8%BF%98%E6%98%AF%E8%AF%B4%E5%BF%85%E9%A1%BB%E5%AE%9A%E4%B9%89%E5%9C%A8-A-%E6%A0%87%E7%AD%BE%E7%9A%84%E5%89%8D%E9%9D%A2%EF%BC%9F"><span class="toc-number">1.0.16.</span> <span class="toc-text">MyBatis 映射文件中，如果 A 标签通过 include 引用了 B 标签的内容，请问，B 标签能否定义在 A 标签的后面，还是说必须定义在 A 标签的前面？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%AE%80%E8%BF%B0-MyBatis-%E7%9A%84-xml-%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%E5%92%8C-MyBatis-%E5%86%85%E9%83%A8%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B9%8B%E9%97%B4%E7%9A%84%E6%98%A0%E5%B0%84%E5%85%B3%E7%B3%BB%EF%BC%9F"><span class="toc-number">1.0.17.</span> <span class="toc-text">简述 MyBatis 的 xml 映射文件和 MyBatis 内部数据结构之间的映射关系？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%AF%B4-MyBatis-%E6%98%AF%E5%8D%8A%E8%87%AA%E5%8A%A8-ORM-%E6%98%A0%E5%B0%84%E5%B7%A5%E5%85%B7%EF%BC%9F%E5%AE%83%E4%B8%8E%E5%85%A8%E8%87%AA%E5%8A%A8%E7%9A%84%E5%8C%BA%E5%88%AB%E5%9C%A8%E5%93%AA%E9%87%8C%EF%BC%9F"><span class="toc-number">1.0.18.</span> <span class="toc-text">为什么说 MyBatis 是半自动 ORM 映射工具？它与全自动的区别在哪里？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%96%87%E7%AB%A0%E6%8E%A8%E8%8D%90"><span class="toc-number">1.0.19.</span> <span class="toc-text">文章推荐</span></a></li></ol></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2024/02/c60470b9a892.html" title="Java集合使用注意事项总结">Java集合使用注意事项总结</a><time datetime="2024-02-03T04:58:22.000Z" title="发表于 2024-02-03 12:58:22">2024-02-03</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2024/02/81fb7a201f29.html" title="无题">无题</a><time datetime="2024-02-03T03:15:31.812Z" title="发表于 2024-02-03 11:15:31">2024-02-03</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2024/01/5737c1ec69a9.html" title="Wed Jan 17 2024 00:00:00 GMT+0800 (中国标准时间)">Wed Jan 17 2024 00:00:00 GMT+0800 (中国标准时间)</a><time datetime="2024-01-31T06:56:16.000Z" title="发表于 2024-01-31 14:56:16">2024-01-31</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2024/01/f510db7d2f19.html" title="Spring常见面试题总结">Spring常见面试题总结</a><time datetime="2024-01-31T06:55:58.000Z" title="发表于 2024-01-31 14:55:58">2024-01-31</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2024/01/9be065e9f288.html" title="redis 面试">redis 面试</a><time datetime="2024-01-31T06:55:55.000Z" title="发表于 2024-01-31 14:55:55">2024-01-31</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2023 - 2024 By 十一星野</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="translateLink" type="button" title="简繁转换">简</button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside-config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="/js/tw_cn.js"></script><script src="https://cdn.staticfile.org/fancyapps-ui/5.0.32/fancybox/fancybox.umd.min.js"></script><script src="https://cdn.staticfile.org/instant.page/5.2.0/instantpage.min.js" type="module"></script><div class="js-pjax"></div><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div><div id="local-search-stats-wrap"></div></div></div><div id="search-mask"></div><script src="/js/search/local-search.js"></script></div></div></body></html>